#ifndef ASTARNODE_HPP
# define ASTARNODE_HPP

# include <iostream>

# include "Puzzle.hpp"

class AStarNode
{
public:
    AStarNode(Puzzle& p, AStarNode* parent = NULL);
    AStarNode(AStarNode const & cp);
    virtual ~AStarNode();

    AStarNode& operator=(AStarNode const & cp);

    friend std::ostream& operator<<(std::ostream& s, AStarNode const & node)
    {
        s   << "A* node: " << node.getTotalCost() << " (" << node.getRCost() << " - " << node.getHCost() << ")" << std::endl
                << node.getPuzzle();
        /*if (node._parent != NULL)
            s << "parent: " << std::endl << node._parent->getPuzzle() << std::endl; */
        return s;
    }

public:
    int computeCost(Puzzle const & solution);

public:
    int getRCost() const;
    int getHCost() const;
    int getTotalCost() const;
    Puzzle& getPuzzle();
    Puzzle const & getPuzzle() const;
    AStarNode* getParent();
    void setPuzzle(Puzzle const & p);
    void setRCost(int cost);
    void setHCost(int cost);
    void setParent(AStarNode* parent);

private:
    Puzzle _puzzle;
    AStarNode* _parent;
    bool _isCostComputed;
    int _RCost;
    int _HCost;
};

inline bool operator==(AStarNode const & n1, AStarNode const & n2)
{
    if (n1.getPuzzle() == n2.getPuzzle())
        return true;
    return false;
}

inline bool operator<(AStarNode const & n1, AStarNode const & n2)
{
    if (n1.getTotalCost() > n2.getTotalCost())
        return true;
    return false;
}

struct HashNode
{
    inline size_t operator()(AStarNode const &) const
    {
        return 0;
    }
};

#endif // ASTARNODE_HPP
